package xyz.zcq.zcqrpc.server.tcp;

import cn.hutool.core.util.IdUtil;
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.net.NetClient;
import io.vertx.core.net.NetSocket;
import xyz.zcq.zcqrpc.config.RpcConfig;
import xyz.zcq.zcqrpc.model.RpcRequest;
import xyz.zcq.zcqrpc.model.RpcResponse;
import xyz.zcq.zcqrpc.model.ServiceMetaInfo;
import xyz.zcq.zcqrpc.protocol.*;

import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

/**
 * Vertx Tcp 客户端
 */
public class VertxTcpClient {

    /**
     * 发送请求，获取响应
     *
     * @param rpcConfig
     * @param rpcRequest
     * @param selectServiceMetaInfo
     * @return
     * @throws InterruptedException
     * @throws ExecutionException
     */
    public static RpcResponse doRequest(RpcConfig rpcConfig, RpcRequest rpcRequest, ServiceMetaInfo selectServiceMetaInfo) throws InterruptedException, ExecutionException {
        NetClient netClient = Vertx.vertx().createNetClient();
        CompletableFuture<RpcResponse> completableFuture = new CompletableFuture<>();
        netClient.connect(selectServiceMetaInfo.getServicePort(), selectServiceMetaInfo.getServiceHost(), (asyncResult) -> {
            if (asyncResult.succeeded()) {
                System.out.println("Connected to TCP server");
                NetSocket netSocket = asyncResult.result();
                // 发送数据
                ProtocolMessage<Object> reqPm = new ProtocolMessage<>();
                ProtocolMessage.Header header = new ProtocolMessage.Header();
                header.setMagic(ProtocolConstant.PROTOCOL_MAGIC);
                header.setVersion(ProtocolConstant.PROTOCOL_VERSION);
                header.setSerializer((byte) ProtocolMessageSerializerEnum.getByValue(rpcConfig.getSerializer()).getKey());
                header.setType((byte) ProtocolMessageTypeEnum.REQUEST.getKey());
                header.setRequestId(IdUtil.getSnowflakeNextId());
                reqPm.setHeader(header);
                reqPm.setBody(rpcRequest);
                try {
                    netSocket.write(ProtocolMessageEncoder.encode(reqPm));
                } catch (IOException e) {
                    throw new RuntimeException("协议消息编码错误");
                }
                // 接收响应
                TcpBufferHandlerWrapper tcpBufferHandlerWrapper = new TcpBufferHandlerWrapper((buffer) -> {
                    try {
                        ProtocolMessage<RpcResponse> resPm = (ProtocolMessage<RpcResponse>) ProtocolMessageDecoder.decode(buffer);
                        completableFuture.complete(resPm.getBody());
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                });
                netSocket.handler(tcpBufferHandlerWrapper);
            } else {
                System.err.println("Failed to connect to TCP server");
            }
        });

        RpcResponse rpcResponse = completableFuture.get();
        return rpcResponse;
    }

    public void start(int port) {
        NetClient netClient = Vertx.vertx().createNetClient();

        netClient.connect(port, "localhost", (asyncResult) -> {
            if (asyncResult.succeeded()) {
                System.out.println("Connected to TCP server");
                NetSocket netSocket = asyncResult.result();
                for (int i = 0; i < 1000; i++) {
                    Buffer buffer = Buffer.buffer();
                    String s = "Hello, server!Hello, server!Hello, server!Hello, server!";
                    buffer.appendInt(0);
                    buffer.appendInt(s.getBytes().length);
                    buffer.appendBytes(s.getBytes());
                    netSocket.write(buffer);
                }
                netSocket.handler(buffer -> {
                    System.out.println("Received response from server: " + buffer.toString());
                });
            } else {
                System.err.println("Failed to connect to TCP server");
            }
        });
    }

    public static void main(String[] args) {
        new VertxTcpClient().start(8888);
    }

}
